﻿ 
#include <iostream>
#include <algorithm>

using namespace std;

/*
https://www.papamelon.com/problem/364


有 N 个农场，贝茜在 1 号农场。
有 M条道路，保证将所有农场和 1 号农场连接起来（直接或间接）。
现在我们要挑选其中的一些路（某些路可以重复走多次），将所有农场都经过一遍（不关心经过的顺序）。
显然，有很多种行走的方案。现在让我们选一种方案，使得经过的道路中的最长边最短。
输出最长边的长度。

输入
第一行两个整数 N(2≤N≤2000),M(1≤M≤10000)，分别表示农场和道路的数量
接下来 M 行，每行三个整数 A,B,L,(1≤A,B≤N,1≤L≤1,000,000,000)
输出
一行，一个整数，表示从 11 访问完其他所有农场，经过的最短的最长边的长度
样例 1
输入
3 3
1 2 23
2 3 1000
1 3 43
输出
43

*/

const int INF = 0x3f3f3f3f;
const int M = 20010;
const int N = 2010;
int n, m;
int p[N];

struct Edge
{
	int a, b, w;

	bool operator< (const Edge &W)const
	{
		return w < W.w;
	}
}edges[M];


int find(int x)
{
	if (p[x] != x) p[x] = find(p[x]);
	return p[x];
}

int kruskal()
{
	sort(edges, edges + 2*m);

	for (int i = 1; i <= n; i++) p[i] = i;    // 初始化并查集

	int res = 0, cnt = 0;
	for (int i = 0; i < 2*m; i++)
	{
		int a = edges[i].a, b = edges[i].b, w = edges[i].w;

		a = find(a), b = find(b);
		if (a != b)
		{
			p[a] = b;
			res = max(res,w);
			cnt++;
		}
	}

	return res;
}


int main()
{
	cin >> n >> m;
	for (int i = 0; i < m; i++) {
		int a, b, w;
		cin >> a >> b >> w;
		edges[i * 2].a = a; edges[i * 2].b = b; edges[i * 2].w = w;
		edges[i * 2 + 1].a = b, edges[i * 2 + 1].b = a, edges[i * 2 + 1].w = w;
	}

	cout << kruskal() << endl;

	return 0;
}

 